#ifndef INST_H
#define INST_H

#define OPCODE_LOAD         0x00
#define OPCODE_LOAD_FP_VP   0x01
#define OPCODE_CUSTOM_0     0x02
#define OPCODE_MISSC_MEM    0x03
#define OPCODE_OP_IMM       0x04
#define OPCODE_AUIPC        0x05
#define OPCODE_OP_IMM_32    0x06
#define OPCODE_48B_0        0x07

#define OPCODE_STORE        0x08
#define OPCODE_STORE_FP_VP  0x09
#define OPCODE_CUSTOM_1     0x0A
#define OPCODE_AMO          0x0B
#define OPCODE_OP           0x0C
#define OPCODE_LUI          0x0D
#define OPCODE_OP_32        0x0E
#define OPCODE_64B          0x0F

#define OPCODE_MADD         0x10
#define OPCODE_MSUB         0x11
#define OPCODE_NMSUB        0x12
#define OPCODE_NMADD        0x13
#define OPCODE_OP_FP        0x14
#define OPCODE_VECTOR       0x15
#define OPCODE_CUSTOM_2     0x16
#define OPCODE_48B_1        0x17

#define OPCODE_BRANCH       0x18
#define OPCODE_JALR         0x19
#define OPCODE_RESERVED_0   0x1A
#define OPCODE_JAL          0x1B
#define OPCODE_SYSTEM       0x1C
#define OPCODE_RESERVED_1   0x1D
#define OPCODE_CUSTOM_3     0x1E
#define OPCODE_80B          0x1F

#define length(inst) ((inst & 0x3))
#define opcode(inst) ((inst >>  2) & 0x1f)
#define funct3(inst) ((inst >> 12) & 0x7 )
#define funct7(inst) ((inst >> 25) & 0x7f)
#define rs1(inst)    ((inst >> 15) & 0x1f)
#define rs2(inst)    ((inst >> 20) & 0x1f)
#define rs3(inst)    ((inst >> 27) & 0x1f)
#define rd(inst)     ((inst >> 7 ) & 0x1f)
#define funct6(inst) ((inst >> 26) & 0x1f)
#define vm(inst)     ((inst >> 25) & 0x1 )
#define aq(inst)     ((inst >> 26) & 0x1 )
#define rl(inst)     ((inst >> 25) & 0x1 )

#define Imm_I(inst) (((int64_t)(int32_t) (inst & 0xfff00000)) >> 20)

#define Imm_S(inst) (((int64_t)(int32_t)(inst & 0xfe000000) >> 20) \
                    | ((inst >> 7) & 0x1f))

#define Imm_B(inst) (((int64_t)(int32_t)(inst & 0x80000000) >> 19) \
                    | ((inst & 0x80) << 4)          \
                    | ((inst >> 20) & 0x7e0)        \
                    | ((inst >> 7) & 0x1e))         

#define Imm_U(inst) ((int64_t)(int32_t)(inst & 0xfffff000))

#define Imm_J(inst) ((uint64_t)((int64_t)(int32_t)(inst & 0x80000000) >> 11) \
                    | (inst & 0xff000)          \
                    | ((inst >> 9) & 0x800)     \
                    | ((inst >> 20) & 0x7fe))

#define shamt(inst) (Imm_I(inst) & 0x1f)

#define csrAddr(inst) ((inst & 0xfff00000) >> 20)


char const * riscv_abiX[] = { // Application Binary Interface registers
        "$0", "ra",  "sp",  "gp",
        "tp", "t0",  "t1",  "t2",
        "s0", "s1",  "a0",  "a1",
        "a2", "a3",  "a4",  "a5",
        "a6", "a7",  "s2",  "s3",
        "s4", "s5",  "s6",  "s7",
        "s8", "s9", "s10", "s11",
        "t3", "t4",  "t5",  "t6",
};


#endif